home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Software Vault: The Gold Collection
/
Software Vault - The Gold Collection (American Databankers) (1993).ISO
/
cdr46
/
strx221.zip
/
STR.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1993-05-18
|
24KB
|
926 lines
//
// str.cpp : str class implementation
// Author : Roy S. Woll
//
// Copyright (c) 1993 by Roy S. Woll
// You may distribute this source freely as long as you leave all files
// in their original form, including the copyright notice as is.
//
//
// Version 2.2 5/12/93
// Fixed substr assignment problem. --> str = substr
// Add member function read, lowercase,
// uppercase, and variations of pad and strip.
//
// Version 2.11 3/17/93
// Friend operator ">>" changed to use str's buffer if > 256.
// Assign operator optimized to not copy referenced data.
// Fix - Remove member function now transfers only necessary characters
//
// Version 2.00 12/5/92
// Support searching/replacing, regular expressions, case sensitivity
//
// Fixed the following bugs.
// 1. Fixed size strings
// 2. Concatenating a substr
//
// Changed member functions pad/strip to modify instance, and introduced
// friend functions pad/strip.
//
// Version 1.00 10/20/92
//
#include <ctype.h>
#include <string.h>
#include <iostream.h>
#include <iomanip.h>
#include <assert.h>
#include "str.h"
#include "dynstream.h"
int strnicmp(const char * s1, const char * s2, unsigned n);
int stricmp(const char * s1, const char * s2);
char * strlwr(char *);
char * strupr(char *);
inline int min(int x, int y){if (x<y) return x; else return y;}
inline int max(int x, int y){if (x>y) return x; else return y;}
// Define macro used to adjust internal debugging counters for object
#ifdef DEBUG_STR
#define STR_SUB_COUNTERS(count) count--;
#define STR_ADD_COUNTERS(count) count++;Total##count++;
#else
#define STR_SUB_COUNTERS(count)
#define STR_ADD_COUNTERS(count)
#endif
static str::strdata NullData = {0, 0, 1, 0, 1, ""};
// Create and map to new buffer, and if previous buffer exists,
// transfer to new buffer.
// Delete old buffer if unreferenced.
char * str::getNewBuffer(int newbufsize){
return getNewBuffer(length(), newbufsize);
};
char * str::getNewBuffer(int len, int newbufsize)
{
if (data==&NullData){
if (memsize_incr) newbufsize = max(newbufsize, memsize_init);
else newbufsize = memsize_init;
}
else {
if (!memsize_incr) return NULL;
if ((newbufsize>data->cursize) || (!newbufsize) )
newbufsize = max(newbufsize, data->cursize + memsize_incr);
else newbufsize = max(newbufsize, memsize_init);
}
if (!newbufsize) newbufsize = memsize_incr; // don't allow 0 size
strdata * newdata;
init(newdata, newbufsize, 0);
setNewBuffer(newdata, newbufsize, len);
return data->buf;
};
// Map to new buffer and if previous buffer exists, transfer to new buffer
void str::setNewBuffer(strdata * newdata,
int newbufsize, int len){
newdata->curlength = data->curlength;
newdata->strChange = data->strChange;
if (data->mystream) {
// Use existing stream
newdata->mystream = data->mystream;
// update existing stream to map to new buffer
newdata->mystream->rdbuf()->setNewBuffer(newdata->buf, newbufsize);
// update stream length next time stream is called for previous data
if (!data->strChange){
data->strChange = 1;
data->curlength = data->mystream->rdbuf()->out_waiting();
};
// force previous data to have unitialized stream
data->mystream = NULL;
};
memcpy(newdata->buf, data->buf, len);
if (!(--data->refcount)) {
delete data;
STR_SUB_COUNTERS(AllocationCount)
}
data = newdata;
};
void str::init(strdata*& adata, int cursize,
int curlength)
{
STR_ADD_COUNTERS(AllocationCount)
if (!cursize) cursize=STR_DEFAULT_MEMINCR;
adata =
(strdata *) new char [(cursize+1)+
sizeof(strdata)-strdata::STR_DEBUG_BUFSIZE];
if (!adata){
cout << "Failed to allocate memory (" << cursize << ")" << endl;
assert(adata);
};
adata->cursize=cursize;
adata->curlength=curlength;
adata->refcount=1;
adata->mystream=NULL;
adata->strChange=1;
};
// Construct an empty str
str::str (void):
data(&NullData),
memsize_init(0), memsize_incr(STR_DEFAULT_MEMINCR),
flags(defaultFlags)
{
STR_ADD_COUNTERS(ObjectCount)
data->refcount++;
};
// Construct an empty str
str::str (int p_bufsize, int p_incr):
data(&NullData),
memsize_init(p_bufsize), memsize_incr(p_incr),
flags(defaultFlags)
{
STR_ADD_COUNTERS(ObjectCount)
data->refcount++;
};
// Construct a str containing substr, char *
str::str (const char * s1, const char * s2):
memsize_init(0),memsize_incr(STR_DEFAULT_MEMINCR),
flags(defaultFlags)
{
STR_ADD_COUNTERS(ObjectCount)
int len1=(s1 ? strlen(s1) : 0);
int len2=(s2 ? strlen(s2) : 0);
init(data, len1+len2, len1+len2);
memcpy(data->buf, s1, len1);
memcpy(data->buf+len1, s2, len2);
};
// Construct a str containing char *, substr
str::str (const char * s1, const substr& s2):
memsize_init(0),memsize_incr(STR_DEFAULT_MEMINCR),
flags(defaultFlags)
{
STR_ADD_COUNTERS(ObjectCount)
int len1=(s1 ? strlen(s1) : 0);
int len2=s2.length();
init(data, len1+len2, len1+len2);
memcpy(data->buf, s1, len1);
memcpy(data->buf+len1, &s2.mystr->data->buf[s2.posReplace], len2);
};
// Construct a str containing two char *
str::str (const substr& s1, const char * s2):
memsize_init(0),memsize_incr(STR_DEFAULT_MEMINCR),
flags(defaultFlags)
{
STR_ADD_COUNTERS(ObjectCount)
int len1= s1.length();
int len2= (s2 ? strlen(s2) : 0);
init(data, len1+len2, len1+len2);
memcpy(data->buf, &s1.mystr->data->buf[s1.posReplace], len1);
memcpy(data->buf+len1, s2, len2);
};
// Construct a str containing two substr
str::str (const substr& s1, const substr& s2):
memsize_init(0),memsize_incr(STR_DEFAULT_MEMINCR),
flags(defaultFlags)
{
STR_ADD_COUNTERS(ObjectCount)
int len1= s1.length();
int len2= s2.length();
init(data, len1+len2, len1+len2);
memcpy(data->buf, &s1.mystr->data->buf[s1.posReplace], len1);
memcpy(data->buf+len1, &s2.mystr->data->buf[s2.posReplace], len2);
};
// Construct a str containing char *
str::str (const char * s, int p_bufsize, int p_incr):
memsize_init(p_bufsize),memsize_incr(p_incr),
flags(defaultFlags)
{
STR_ADD_COUNTERS(ObjectCount)
if (!s) return;
int curlength, cursize;
if (memsize_incr==0) { // not allowed to expand
curlength = min(strlen(s), memsize_init);
cursize = memsize_init;
}
else {
curlength=strlen(s);
cursize = max(curlength, memsize_init);
};
init(data, cursize, curlength);
memcpy(data->buf, s, curlength);
};
// Construct a str containing str
str::str (const str& s, int p_bufsize, int p_incr):
memsize_init(p_bufsize),memsize_incr(p_incr),
flags(defaultFlags)
{
STR_ADD_COUNTERS(ObjectCount)
if (memsize_incr) {
data = s.data;
data->refcount++;
}
else {
int curlength = min(s.length(), memsize_init);
init(data, memsize_init, curlength);
memcpy(data->buf, s, curlength);
};
};
// Return a ostream that maps to the same buffer as the str
ostream& str::stream(int pos){
return stream().seekp(pos);
};
// Return a ostream that maps to the same buffer as the str
ostream& str::stream(void){
//
// check if need to allocate more memory
//
int allocsize=0;
if (data==&NullData) allocsize = memsize_init; // first time allocating
else if (length()>=size()) allocsize = size()+memsize_incr;
_checkMemAllocation(allocsize);
//
// Create stream if it doesn't exist
// otherwise tell dynstream about me in case it needs to extend buf
//
if (!data->mystream) data->mystream = new dynstream(this);
else data->mystream->rdbuf()->set_str(this);
//
// update stream length if length has been changed by str operators.
// Not done every time in case stream operation was the last operation
// to change the length.
//
if (data->strChange) {
data->mystream->rdbuf()->set_len(data->curlength);
data->strChange=0;
};
return *data->mystream;
};
int str::length(void) const{
if ((!data->strChange) && (data->mystream))
setlength(data->mystream->rdbuf()->out_waiting());
return data->curlength;
};
str::~str (void){
STR_SUB_COUNTERS(ObjectCount)
if (!(--data->refcount)){
STR_SUB_COUNTERS(AllocationCount)
delete data->mystream;
delete data;
};
};
//
// return (const char *)
//
str::operator const char * () const{
data->buf[length()] = 0;
return data->buf;
};
const char * str::operator()(int index) const
{
return (*this)() + index;
}
char& str::operator[](int position) // array indexing
{
if (data->refcount>1) getNewBuffer(data->cursize);
#ifndef SMART_STR_USER
//
// Force string to be null-terminated in case user
// uses the "&" operator to pass a pointer (ie. &mystr[3])
//
if (!data->strChange) return *(char *)(*this)(position);
#endif
return data->buf[position];
}
int str::size(void) const{
return data->cursize;
};
//
// str member = operators
//
str & str::_assign(const char * s, int len)
{
// Get new buffer if necessary, but don't transfer contents.
// This is handled specially, so as to remove the unnecessary transfer.
if ((data->refcount>1) || (size()<len))
getNewBuffer( 0, max(size(),len) );
if (!memsize_incr) len = min(len, size());
memcpy(data->buf, s, len);
setlength(len);
return *this;
};
str& str::operator = (const str& s){
if (this == &s) return *this; // assignment to self
if (data == s.data) return *this; // assignment to self
if (!memsize_incr) return _assign(s, s.length());
dynstream * prevStream=NULL;
if (!(--data->refcount)) { // deallocate old pointer
STR_SUB_COUNTERS(AllocationCount)
//
// try to reuse this stream
//
prevStream = data->mystream;
if (s.data){
if (s.data->mystream) {
delete data->mystream;
prevStream = NULL;
}
}
delete data;
};
data = s.data;
data->refcount++;
//
// Map my stream to point to an existing stream using buffer data->buf
//
if (prevStream) {
data->mystream = prevStream; // what about previous mystream?
//
// update s stream to map to new this stream
//
data->mystream->rdbuf()->setNewBuffer(data->buf, size());
//
// update stream length next time stream is called for previous data
//
data->strChange = 1;
}
return *this;
};
str& str::operator = (const substr& s){
int len = s.mystr->length() - s.posReplace;
if (len>=0) len = min(s.numReplace, len);
return _assign((*s.mystr)(s.posReplace), len);
};
str& str::operator = (const char * s){
return _assign(s, strlen(s));
};
str& str::assign(const char * s, int len){
return _assign(s, min(strlen(s), len));
};
str& str::operator = (const char s){
return _assign(&s, 1);
};
str & str::_concat(const char * s, int len)
{
int mylen = length();
_checkMemAllocation(mylen + len);
if (!memsize_incr) len = min(len, size()-mylen);
memcpy(data->buf + mylen, s, len); //concat
setlength(mylen+len);
return *this;
};
//
// str member += operators
//
str & str::operator += (const str& s){
if (!length()) return *this=s;
return _concat(s, s.length());
};
str & str::operator += (const substr& s){
return _concat(&s.mystr->data->buf[s.posReplace], s.length());
};
str & str::operator += (const char * s){
return _concat(s, strlen(s));
};
str & str::operator += (const char s){
return _concat(&s, 1);
};
//
// str member << operators
//
str& str::operator << (const str& s) { return *this+=s;};
str& str::operator << (const substr& s) { return *this+=s;};
str& str::operator << (const char * s) { return *this+=s;};
str& str::operator << (const char s) { return *this+=s;};
str& str::operator << (const int s){
stream() << s;
return *this;
};
//
// str member + operators
//
str str::operator+(const _SUBSTR & b) const{ return str(*this,b); };
str str::operator+(const str&b) const{ return str(*this,b); };
str str::operator+(const char * b) const{ return str(*this,b); };
str str::operator+(const char b) const{
char buf[2];
buf[0]=b;
buf[1]=0;
return str(*this,buf);
};
//
// istream/ostream friend functions
//
istream& operator >> (istream& stream, str & s){
if (s.memsize_init>256){ // Use str's current data buffer
s = " "; // Gets new buffer if neccessary (ie. reference)
stream.getline(s.data->buf, s.size());
s.setlength(stream.gcount());
if (s[s.length()]==10) // retrieve to end of line
s.setlength(s.length()-1);
}
else {
char buf[256];
stream.getline(buf, 256);
if (buf[stream.gcount()-1]==10) // retrieve to end of line
buf[stream.gcount()-1]=0;
s = buf;
};
return stream;
};
istream& str::read(istream& stream, int count)
{
*this = " "; // Gets new buffer if neccessary (ie. reference)
stream.read(data->buf, min(size(), count));
setlength(stream.gcount());
return stream;
};
ostream& operator << (ostream& stream, const str & s){
return stream << s();
};
str& str::lowercase()
{
_checkMemAllocation();
strlwr(data->buf);
return *this;
}
str& str::uppercase()
{
_checkMemAllocation();
strupr(data->buf);
return *this;
}
//
// uppercase/lowercase friend functions
//
str uppercase(const char * s) {
str newstr(s);
strupr((char *)newstr());
return newstr;
};
str lowercase(const char * s) {
str newstr(s);
strlwr((char *)newstr());
return newstr;
};
//
// pad/strip
//
str& str::padRight(int padsize, char padchar)
{
return pad(padsize, right, padchar);
}
str& str::padLeft(int padsize, char padchar)
{
return pad(padsize, left, padchar);
}
str& str::padBoth(int padsize, char padchar)
{
return pad(padsize, both, padchar);
}
str& str::pad(int padsize, PadStripT t, char padchar){
int len = length();
if (len<padsize) {
_checkMemAllocation(padsize);
if (!memsize_incr) padsize = min(padsize, size());
if (t == right)
memset(&data->buf[len], padchar, padsize-len);
else if (t == both){
int len1 = (padsize-len)/2;
int len2 = (padsize-len+1)/2;
memmove(&data->buf[len1], &data->buf, len);
memset(&data->buf[0], padchar, len1);
memset(&data->buf[len+len1], padchar, len2);
}
else{
int len1 = (padsize-len);
memmove(&data->buf[len1], &data->buf, len);
memset(&data->buf[0], padchar, len1);
}
setlength(padsize);
};
return *this;
}
str& str::stripTrailing(const char * stripchars)
{
return strip(trailing, stripchars);
}
str& str::stripLeading(const char * stripchars)
{
return strip(leading, stripchars);
}
str& str::stripBoth(const char * stripchars)
{
return strip(both, stripchars);
}
str& str::strip(PadStripT t, char stripchar){
int len = length();
int start = 0;
int end = len-1;
if (end<0) return *this;
if ((t == leading) || (t==both)){
for (; start<=end; start++)
if (data->buf[start] != stripchar) break;
};
if ((t == trailing) || (t==both)){
if (data->buf[end] == stripchar) {
for (; end >= start; end--){
if (data->buf[end] != stripchar) break;
};
};
};
if ((end-start+1)<len)
{
_checkMemAllocation();
if (start) memmove(&data->buf[0], &data->buf[start], end-start+1);
setlength(end-start+1);
};
return *this;
};
str& str::strip(PadStripT t, const char * stripchars){
int len = length();
int start = 0;
int end = len-1;
if (end<0) return *this;
if ((t == leading) || (t==both)){
int pos = strspn((*this)(), stripchars);
if (pos>0) start += pos;
};
if ((t == trailing) || (t==both)){
if (strchr(stripchars, data->buf[end])){
for (; end>=start; end--){
if (!strchr(stripchars, data->buf[end])) break;
}
}
};
if ((end-start+1)<len)
{
_checkMemAllocation();
if (start) memmove(&data->buf[0], &data->buf[start], end-start+1);
setlength(end-start+1);
};
return *this;
};
str pad(str s, int padsize, str::PadStripT t, char padchar){
return s.pad(padsize, t, padchar);
};
str strip(str s, str::PadStripT t, const char * stripchars){
return s.strip(t, stripchars);
};
str strip(str s, str::PadStripT t, char stripchar){
return s.strip(t, stripchar);
};
//
// insert/remove
//
int str::insert(int pos, char ch){
char tempstr[2];
tempstr[0] = ch;
tempstr[1] = 0;
return insert(pos, tempstr);
}
int str::insert(int pos, const char * insertStr){
int len = length();
int afterPos = len+1-pos; // number of characters following pos
if (afterPos<0) return 0; // out of range
int insertLen = strlen(insertStr);
_checkMemAllocation( len+insertLen );
if (!memsize_incr) insertLen = min(insertLen, size()-len);
if (insertLen){
if (afterPos)
memmove(&data->buf[pos + insertLen], &data->buf[pos], afterPos);
memmove(&data->buf[pos], insertStr, insertLen);
setlength(len+insertLen);
return 1;
}
else return 0;
};
void str::remove(int pos, int numdel){
int len = length();
if (pos>=len) return;
_checkMemAllocation();
numdel = min(numdel, len-pos);
memmove(&data->buf[pos], &data->buf[pos+numdel], len-(numdel+pos));
setlength(len-numdel);
};
//
// substr member operators/functions
//
_SUBSTR::substr(const str * data, int AposReplace, int AnumReplace):
mystr((str *)data), posReplace(AposReplace), numReplace(AnumReplace){};
_SUBSTR str::operator()(int pos, int numreplace)
{
return substr(this, pos, numreplace);
}
const _SUBSTR str::operator()(int pos, int numreplace) const
{
return substr(this, pos, numreplace);
}
int _SUBSTR::length(void) const{
return min(numReplace, max(0, mystr->length()-posReplace) );
};
str & _SUBSTR::operator = (const char * s){
if (posReplace<0) return *this->mystr;
if (strlen(s)==length()){
mystr->_checkMemAllocation();
memcpy(&mystr->data->buf[posReplace], s, length());
}
else {
mystr->remove(posReplace, numReplace);
mystr->insert(posReplace, s);
};
return *this->mystr;
};
str & _SUBSTR::operator = (const substr& s){
return *this = *s.mystr;
};
str _SUBSTR::operator+(const char * s) const{
return str(*this, s);
};
str _SUBSTR::operator+(const substr& s) const{
return str(*this, s);
};
int _SUBSTR::compare(const char * s) const{
return mystr->strncmp((*this->mystr)(posReplace), s, numReplace);
};
int _SUBSTR::compare(const substr& s) const{
int len = min(numReplace, s.numReplace);
return mystr->strncmp((*this->mystr)(posReplace), (*s.mystr)(s.posReplace), len);
};
int _SUBSTR::operator==(const char *s) const{ return compare(s)==0; };
int _SUBSTR::operator<=(const char *s) const{ return compare(s)<=0; };
int _SUBSTR::operator>=(const char *s) const{ return compare(s)>=0; };
int _SUBSTR::operator!=(const char *s) const{ return compare(s)!=0; };
int _SUBSTR::operator< (const char *s) const{ return compare(s)< 0; };
int _SUBSTR::operator> (const char *s) const{ return compare(s)> 0; };
int _SUBSTR::operator==(const substr& s) const{ return compare(s)==0; };
int _SUBSTR::operator<=(const substr& s) const{ return compare(s)<=0; };
int _SUBSTR::operator>=(const substr& s) const{ return compare(s)>=0; };
int _SUBSTR::operator!=(const substr& s) const{ return compare(s)!=0; };
int _SUBSTR::operator< (const substr& s) const{ return compare(s)< 0; };
int _SUBSTR::operator> (const substr& s) const{ return compare(s)> 0; };
_SUBSTR::operator str() const{
str temp;
temp.assign((*(mystr))(posReplace), numReplace);
return temp;
};
int str::_checkMemAllocation(int requiredLen){
if ((data->refcount<=1) && (size()>=requiredLen)) return 1;
return (getNewBuffer(max(size(), requiredLen))!=NULL);
};
//
// Case sensitivity member functions
//
int str::caseSensitive(void) const { return !(flags & ICASE); }
void str::setCaseSensitive(int val)
{
if (val) flags &= !ICASE;
else flags |= ICASE;
}
void str::setdefaultCaseSensitive(int val)
{
if (val) defaultFlags &= !ICASE;
else defaultFlags |= ICASE;
}
//
// Friend/Global str relational operators
//
str operator + (const char *a, const str&b) { return str(a,b); };
str operator + (const char *a, const _SUBSTR&b){ return str(a,b); };
int compare(const char * a, const str & b) {return ( b.strcmp(a, b) );};
int compare(const str& a, const str & b) {return ( a.strcmp(a, b) );};
int compare(const str& a, const char * b) {return ( a.strcmp(a, b) );};
int operator ==(const char *a, const str&b){return (compare(a,b) == 0); };
int operator >=(const char *a, const str&b){return (compare(a,b) >= 0); };
int operator <=(const char *a, const str&b){return (compare(a,b) <= 0); };
int operator !=(const char *a, const str&b){return (compare(a,b) != 0); };
int operator > (const char *a, const str&b){return (compare(a,b) > 0); };
int operator < (const char *a, const str&b){return (compare(a,b) < 0);};
int operator ==(const char *a, const _SUBSTR &b){ return b==a; };
int operator >=(const char *a, const _SUBSTR &b){ return b<=a; };
int operator <=(const char *a, const _SUBSTR &b){ return b>=a; };
int operator !=(const char *a, const _SUBSTR &b){ return b!=a; };
int operator > (const char *a, const _SUBSTR &b){ return b<a; };
int operator < (const char *a, const _SUBSTR &b){ return b>a; };
//
// Member str relational operators
//
int str::operator==(const char *b) const{ return (compare(*this,b) == 0); };
int str::operator<=(const char *b) const{ return (compare(*this,b) <= 0); };
int str::operator>=(const char *b) const{ return (compare(*this,b) >= 0); };
int str::operator!=(const char *b) const{ return (compare(*this,b) != 0); };
int str::operator> (const char *b) const{ return (compare(*this,b) > 0); };
int str::operator< (const char *b) const{ return (compare(*this,b) < 0); };
int str::operator==(const str &b) const{ return (compare(*this,b) == 0); };
int str::operator<=(const str &b) const{ return (compare(*this,b) <= 0); };
int str::operator>=(const str &b) const{ return (compare(*this,b) >= 0); };
int str::operator!=(const str &b) const{ return (compare(*this,b) != 0); };
int str::operator> (const str &b) const{ return (compare(*this,b) > 0); };
int str::operator< (const str &b) const{ return (compare(*this,b) < 0); };
int str::strncmp(const char * s1, const char * s2, int n) const{
if (caseSensitive()) return ::strncmp(s1,s2,n);
else return ::strnicmp(s1,s2,n);
};
int str::strcmp(const char * s1, const char * s2) const{
if (caseSensitive()) return ::strcmp(s1,s2);
else return ::stricmp(s1,s2);
};
int str::defaultFlags = 0;
#ifdef DEBUG_STR
int str::dynstreamCount=0;
int str::ObjectCount=0;
int str::AllocationCount=0;
int str::TotalObjectCount=0;
int str::TotalAllocationCount=0;
#endif